﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using Extensibility;
using EnvDTE;
using EnvDTE80;


namespace StringFormatterAddin
{
    public class CodeExpression
    {
        public int StartOffset;
        public int EndOffset;
        public string Text = "";
        public EditPoint sp;
        public EditPoint ep;
        public List<CodeExpression> childExpressions = new List<CodeExpression>();

        public void Move(int delta)
        {
            sp.CharRight(delta);
            ep.CharRight(delta);
            StartOffset += delta;
            EndOffset += delta;
        }

        public bool HasPoint(VirtualPoint point)
        {
            if ((StartOffset <= point.AbsoluteCharOffset) && (EndOffset >= point.AbsoluteCharOffset))
            {
                return true;
            }
            return false;
        }

        public CodeExpression(EditPoint startPoint, EditPoint endPoint)
        {
            StartOffset = startPoint.AbsoluteCharOffset;
            EndOffset = endPoint.AbsoluteCharOffset;
            Text = startPoint.GetText(endPoint);
            sp = startPoint.CreateEditPoint();
            ep = endPoint.CreateEditPoint();
        }

        public static List<CodeExpression> GetExpressions(CodeElement c)
        {
            List<CodeExpression> exps = new List<CodeExpression>();
            EditPoint edp = c.StartPoint.CreateEditPoint();
            EditPoint startOfExps = c.StartPoint.CreateEditPoint();
            //кавычки
            bool wasQuote = false;
            //скобки
            //bool wasBrecket = false;
            //фигурные скобки
            int wasBraces = 0;
            while (edp.LessThan(c.EndPoint))
            {
                string charT = edp.GetText(1);
                if (wasBraces>0)
                {
                    if ((charT == "}") && (!wasQuote))
                    {
                        wasBraces--;
                        if (wasBraces == 0)
                        {
                            exps[exps.Count - 1].childExpressions = GetInnerExpressions(startOfExps, edp);
                            edp.CharRight(2);
                            startOfExps = edp.CreateEditPoint();
                            continue;
                        }
                        else
                        {
                            edp.CharRight(1);
                            continue;
                        }
                    }
                    if ((charT == "{") && (!wasQuote))
                    {
                        wasBraces++;
                        edp.CharRight(1);
                        continue;
                    }
                }
                else
                {
                    if ((charT == "{") && (!wasQuote))
                    {
                        wasBraces++;
                        CodeExpression ex = new CodeExpression(startOfExps, edp);
                        exps.Add(ex);
                        edp.CharRight(1);
                        startOfExps = edp.CreateEditPoint();
                        continue;
                    }
                    if (charT == "\"")
                    {
                        if (wasQuote)
                        {
                            //это заканчивающая кавычка или внутренняя
                            string charP = edp.GetText(-1);
                            if (charP != "\\")
                            {
                                wasQuote = false;
                                edp.CharRight(1);
                                continue;
                            }
                        }
                        else
                        {
                            //это открывающая кавычка
                            wasQuote = true;
                            edp.CharRight(1);
                            continue;
                        }
                    }
                    if ((charT == ";") && (!wasQuote))
                    {
                        edp.CharRight(1);
                        CodeExpression ex = new CodeExpression(startOfExps, edp);
                        exps.Add(ex);
                        startOfExps = edp.CreateEditPoint();
                        continue;
                    }
                }
                edp.CharRight(1);
            }
            if ((startOfExps.AbsoluteCharOffset < edp.AbsoluteCharOffset - 1) && (startOfExps.LessThan(c.EndPoint)))
            {
                CodeExpression ex = new CodeExpression(startOfExps, edp);
                exps.Add(ex);
            }
            return exps;
        }

        private static List<CodeExpression> GetInnerExpressions(EditPoint start, EditPoint end)
        {
            List<CodeExpression> exps = new List<CodeExpression>();
            EditPoint edp = start.CreateEditPoint();
            EditPoint startOfExps = start.CreateEditPoint();
            EditPoint endP = end.CreateEditPoint();
            endP.CharLeft(1);
            //кавычки
            bool wasQuote = false;
            //скобки
            //bool wasBrecket = false;
            //фигурные скобки
            int wasBraces = 0;
            while (edp.LessThan(endP))
            {
                string charT = edp.GetText(1);
                if (wasBraces > 0)
                {
                    if ((charT == "}") && (!wasQuote))
                    {
                        wasBraces--;
                        if (wasBraces == 0)
                        {
                            exps[exps.Count - 1].childExpressions = GetInnerExpressions(startOfExps, edp);
                            edp.CharRight(2);
                            startOfExps = edp.CreateEditPoint();
                            continue;
                        }
                        else
                        {
                            edp.CharRight(1);
                            continue;
                        }
                    }
                    if ((charT == "{") && (!wasQuote))
                    {
                        wasBraces++;
                        edp.CharRight(1);
                        continue;
                    }
                }
                else
                {
                    if ((charT == "{") && (!wasQuote))
                    {
                        wasBraces++;
                        CodeExpression ex = new CodeExpression(startOfExps, edp);
                        exps.Add(ex);
                        edp.CharRight(1);
                        startOfExps = edp.CreateEditPoint();
                        continue;
                    }
                    if (charT == "\"")
                    {
                        if (wasQuote)
                        {
                            //это заканчивающая кавычка или внутренняя
                            string charP = edp.GetText(-1);
                            if (charP != "\\")
                            {
                                wasQuote = false;
                                edp.CharRight(1);
                                continue;
                            }
                        }
                        else
                        {
                            //это открывающая кавычка
                            wasQuote = true;
                            edp.CharRight(1);
                            continue;
                        }
                    }
                    if ((charT == ";") && (!wasQuote))
                    {
                        edp.CharRight(1);
                        CodeExpression ex = new CodeExpression(startOfExps, edp);
                        exps.Add(ex);
                        startOfExps = edp.CreateEditPoint();
                        continue;
                    }
                }
                edp.CharRight(1);
            }
            if ((startOfExps.AbsoluteCharOffset < edp.AbsoluteCharOffset - 1) && (startOfExps.LessThan(endP)))
            {
                CodeExpression ex = new CodeExpression(startOfExps, edp);
                exps.Add(ex);
            }
            return exps;
        }
    }
}
